package com.foresee.security;


import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;

/**
 * RSA 加密工具
 * @author syk
 */
public class RSAUtils {

    public static final String KEY_ALGORITHM = "RSA";
    public static final String PUBLIC_KEY = "/securityKey/RSAPublicKey";
    public static final String PRIVATE_KEY = "/securityKey/RSAPrivateKey";


    /**
     * 生成public key and private key
     * @throws Exception
     */
    public static void GenKeys() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);

        SecureRandom secureRandom = new SecureRandom(new Date().toString().getBytes());
        keyPairGenerator.initialize(1024,secureRandom);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        FileOutputStream fos = new FileOutputStream(PUBLIC_KEY);
        fos.write(publicKeyBytes);
        fos.close();
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        fos = new FileOutputStream(PRIVATE_KEY);
        fos.write(privateKeyBytes);
        fos.close();
    }


    /**
     * 获取 public key 加密使用(暴露给外部使用)
     * @param publicKeyPath 生成的公钥路径(用于获取Public key) 设置到了resources下
     * @return 公钥
     * @throws Exception
     */
    public static PublicKey publicKey(String publicKeyPath) throws Exception {
        InputStream is = com.foresee.security.RSAUtils.class.getResourceAsStream(publicKeyPath);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int n = 0;
        while (-1!=(n=is.read(buffer))){
            outputStream.write(buffer,0,n);
        }
        byte[] keyBytes = outputStream.toByteArray();

        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance(KEY_ALGORITHM);
        return kf.generatePublic(spec);
    }

    /**
     * 获取 private key 解密使用(解密一方自己保存)
     * @param privateKeyPath 生成的私钥路径 设置到了resources下
     * @return 私钥
     * @throws Exception
     */
    public static PrivateKey privateKey(String privateKeyPath) throws Exception {
        InputStream is = com.foresee.security.RSAUtils.class.getResourceAsStream(privateKeyPath);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int n = 0;
        while (-1!=(n=is.read(buffer))){
            outputStream.write(buffer,0,n);
        }
        byte[] keyBytes = outputStream.toByteArray();
        PKCS8EncodedKeySpec spec =new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance(KEY_ALGORITHM);
        return kf.generatePrivate(spec);
    }


    /**
     * 使用公钥加密
     * @param plainData 原始数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] plainData) throws Exception {
        RSAPublicKey publicKey = (RSAPublicKey)publicKey(PUBLIC_KEY);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        byte[] encryptedData = cipher.doFinal(plainData);
        return encryptedData;
    }

    /**
     * 使用私钥解密
     * @param encrptedData 加密后的数据
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] encrptedData) throws Exception {
        RSAPrivateKey privateKey = (RSAPrivateKey)privateKey(PRIVATE_KEY);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] plainData = cipher.doFinal(encrptedData);
        return plainData;
    }


    /**
     * 解析base64字符串 获取原始字符串key
     * @param base64Key
     * @return
     * @throws Exception
     */
    public static String parseKey(String base64Key) throws Exception {
        org.apache.commons.codec.binary.Base64 base64 = new org.apache.commons.codec.binary.Base64();
        String metaKey = new String(RSAUtils.decrypt(base64.decode(base64Key)));
        return metaKey;
    }

    /**
     * string 类型的key 使用rsa 加密后 转换成 base64字符串
     * @param metaKey
     * @return
     * @throws Exception
     */
    public static String toBase64Key(String metaKey) throws Exception {
        org.apache.commons.codec.binary.Base64 base64 = new org.apache.commons.codec.binary.Base64();
        // key 使用RSA 加密
        byte[] encryptedKey = RSAUtils.encrypt(metaKey.getBytes());
        //byte[] key 转换成string 返回客户端
        String encryptedTextKey = base64.encodeToString(encryptedKey);
        return encryptedTextKey;
    }




}
